---
title: Tutoriel - Étendre avec les collections de contenu
description: Convertir le code du didacticiel Construire un blog du routage basé sur les fichiers aux collections de contenu.

i18nReady: true
---
import PackageManagerTabs from '~/components/tabs/PackageManagerTabs.astro';
import Box from '~/components/tutorial/Box.astro';
import MultipleChoice from '~/components/tutorial/MultipleChoice.astro';
import PreCheck from '~/components/tutorial/PreCheck.astro';
import Option from '~/components/tutorial/Option.astro';
import { Steps } from '@astrojs/starlight/components';

**Les collections de contenu** sont un moyen puissant de gérer des groupes de contenus similaires, tels que des articles de blog. Les collections permettent d'organiser vos documents, de valider votre frontmatter YAML et de fournir une sécurité de type TypeScript automatique pour l'ensemble de votre contenu (même si vous n'écrivez pas de TypeScript vous-même).

<PreCheck>
  - Déplacez votre dossier d'articles de blog dans `src/content/`
  - Créez un schéma pour définir le contenu de vos articles de blog.
  - Utiliser `getCollection()` pour obtenir le contenu et les métadonnées des articles de blog
</PreCheck>

## Prérequis

Vous aurez besoin **d'un projet Astro existant avec des fichiers Markdown ou MDX dans le dossier `src/pages/`**.

Ce tutoriel utilise le [projet fini du tutoriel Construire un blog](https://github.com/withastro/blog-tutorial-demo) pour démontrer la conversion d'un blog en collections de contenus. Vous pouvez forker et utiliser cette base de code localement, ou compléter le tutoriel dans le navigateur en [éditant le code du tutoriel sur les blogs dans StackBlitz](https://stackblitz.com/github/withastro/blog-tutorial-demo/tree/complete?file=src%2Fpages%2Findex.astro).

Vous pouvez également suivre ces étapes avec votre propre projet Astro, mais vous devrez adapter les instructions à votre base de code.

Nous vous recommandons d'utiliser notre exemple de projet pour compléter ce court tutoriel dans un premier temps. Ensuite, vous pourrez utiliser ce que vous avez appris pour créer des collections de contenu dans votre propre projet.

## Code du tutoriel Construire un blog

Dans le [Tutoriel d'introduction à la création d'un blog](/fr/tutorial/0-introduction/), vous avez découvert le [routage intégré basé sur les fichiers](/fr/guides/routing/#routes-statiques) d'Astro : tout fichier `.astro`, `.md`, ou `.mdx` situé dans le dossier `src/pages/` devient automatiquement une page de votre site.

Pour créer votre premier article de blog à `https://exemple.com/posts/post-1/`, vous avez créé un dossier `/posts/` et ajouté le fichier `post-1.md`. Vous avez ensuite ajouté un nouveau fichier Markdown à ce dossier chaque fois que vous vouliez ajouter un nouvel article de blog à votre site.


## Pages vs Collections

Même si vous utilisez des collections de contenus, vous utiliserez toujours le dossier `src/pages/` pour les pages individuelles, comme votre page À propos de moi. Mais en déplaçant vos articles de blog vers le dossier spécial `src/content/`, vous pourrez utiliser des API plus puissantes et plus performantes pour générer l'index de vos articles de blog et afficher vos articles individuels.

En même temps, vous recevrez de meilleurs conseils et une autocomplétion dans votre éditeur de code parce que vous aurez un **[schéma](/fr/guides/content-collections/#définition-dun-schéma-de-collection)** pour définir une structure commune pour chaque article qu'Astro vous aidera à mettre en application. Dans votre schéma, vous pouvez spécifier quand des propriétés sont requises, comme une description ou un auteur, et quel type de données chaque propriété doit être, comme une chaîne ou un tableau. De nombreuses erreurs sont ainsi détectées plus rapidement, et des messages d'erreur descriptifs vous indiquent exactement la nature du problème.

Pour en savoir plus sur les [collections de contenu Astro](/fr/guides/content-collections/), lisez notre guide, ou commencez avec les instructions ci-dessous pour convertir un blog basique de `src/pages/posts/` à `src/content/posts/`.

<Box icon="question-mark">
### Testez vos connaissances

1. Quel type de page conserveriez-vous dans `src/pages/` ?

    <MultipleChoice>
      <Option>
        Les articles de blog qui contiennent tous la même structure de base et les mêmes métadonnées.
      </Option>
      <Option>
        Pages de produits dans un site de commerce 
      </Option>
      <Option isCorrect>
        Une page de contact, car vous n'avez pas plusieurs pages similaires de ce type.
      </Option>
    </MultipleChoice>

2. Quel n'est **pas** l'avantage de déplacer les articles de blog vers une collection de contenus ?

    <MultipleChoice>
      <Option isCorrect>
         Des pages sont automatiquement créées pour chaque fichier
      </Option>
      <Option>
        Meilleurs messages d'erreur, car Astro en sait plus sur chaque fichier.
      </Option>
      <Option>
        Meilleure récupération des données, avec une fonction plus performante
      </Option>
    </MultipleChoice>

3. Les collections de contenu utilisent TypeScript...
    <MultipleChoice>
      <Option>
        Pour que je me sente mal
      </Option>
      <Option isCorrect>
        Pour comprendre mon projet, même si je n'écris pas de TypeScript
      </Option>
      <Option>
        Seulement si j'ai la configuration `strict` ou `strictest` définie
      </Option>
    </MultipleChoice>

</Box>

## Extension du tutoriel sur le blog avec des collections de contenus

Les étapes ci-dessous vous montrent comment étendre le produit final du tutoriel Construire un blog en créant une collection de contenu pour les articles du blog.

### Mise à jour des dépendances 

<Steps>
1. Mettez à jour la dernière version d'Astro, et mettez à jour toutes les intégrations vers leurs dernières versions en exécutant les commandes suivantes dans votre terminal :

    <PackageManagerTabs>
      <Fragment slot="npm">
      ```shell
      # Mettre à jour Astro v4.x
      npm install astro@latest

      # Exemple : mise à jour du tutoriel du blog Intégration de Preact
      npm install @astrojs/preact@latest
      ```
      </Fragment>
      <Fragment slot="pnpm">
      ```shell
      # Mettre à jour Astro v4.x
      pnpm add astro@latest

    # Exemple : mise à jour du tutoriel du blog Intégration de Preact
      pnpm add @astrojs/preact@latest
      ```
      </Fragment>
      <Fragment slot="yarn">
      ```shell
      # Mettre à jour Astro v4.x
      yarn add astro@latest

    # Exemple : mise à jour du tutoriel du blog Intégration de Preact
      yarn add @astrojs/preact@latest
      ```
      </Fragment>
    </PackageManagerTabs>

    :::tip
    Si vous utilisez votre propre projet, veillez à mettre à jour toutes les dépendances que vous avez installées. L'exemple de code du tutoriel sur les blogs n'utilise que l'intégration Preact.
    :::

2. Le tutoriel du blog utilise le paramètre TypeScript `base` (le moins strict). Pour utiliser les collections de contenus, vous devez [configurer TypeScript](/fr/guides/content-collections/#configuration-de-typescript) pour les collections de contenus **soit** en utilisant le paramètre `strict` ou `strictest`, **soit** en ajoutant deux options dans `tsconfig.json`.

    Afin d'utiliser les collections de contenu sans écrire de TypeScript dans le reste de l'exemple du tutoriel du blog, ajoutez les deux options de configuration TypeScript suivantes au fichier de configuration :

    ```json title="tsconfig.json" ins={5,6}
    {
      // Note : Aucun changement n'est nécessaire si vous utilisez "astro/tsconfigs/strict" ou "astro/tsconfigs/strictest".
      "extends": "astro/tsconfigs/base",
      "compilerOptions": {
        "strictNullChecks": true,
        "allowJs": true
      }
    }
    ```
</Steps>

### Créer une collection pour vos articles de blog

<Steps>
3. Créez une nouvelle **collection** (dossier) appelée `src/content/posts/`.

4. Déplacez tous vos articles de blog existants (fichiers `.md`) de `src/pages/posts/` vers cette nouvelle collection.

5. Créez un fichier `src/content/config.ts` pour [définir un schéma](/fr/guides/content-collections/#définition-dun-schéma-de-collection) pour votre `postsCollection`. Pour le code du tutoriel de blog existant, ajoutez le contenu suivant au fichier pour définir toutes les propriétés frontmatter utilisées dans ses articles de blog :

    ```ts title="src/content/config.ts"
    // Importe les propriétés depuis `astro:content`
    import { z, defineCollection } from "astro:content";
    // Définir un `type` et un `schema` pour chaque collection
    const postsCollection = defineCollection({
        type: 'content',
        schema: z.object({
          title: z.string(),
          pubDate: z.date(),
          description: z.string(),
          author: z.string(),
          image: z.object({
            url: z.string(),
            alt: z.string()
          }),
          tags: z.array(z.string())
        })
    });
    // Exporter un objet `collections` unique pour y enregistrer vos collections
    export const collections = {
      posts: postsCollection,
    };
    ```

6. Pour qu'Astro reconnaisse votre schéma, quittez le serveur de développement (`CTRL + C`) et exécutez la commande suivante : [`npx astro sync`](/fr/reference/cli-reference/#astro-sync). Ceci définira le module `astro:content` pour l'API Content Collections. Redémarrez le serveur de développement pour continuer le tutoriel.
</Steps>

### Générer des pages à partir d'une collection

<Steps>
7. Créez un fichier de page appelé `src/pages/posts/[...slug].astro`. Vos fichiers Markdown et MDX ne deviennent plus automatiquement des pages en utilisant le routage basé sur les fichiers d'Astro lorsqu'ils se trouvent dans une collection, vous devez donc créer une page responsable de la génération de chaque article de blog.

8. Ajoutez le code suivant pour [interroger votre collection](/fr/guides/content-collections/#interroger-les-collections) pour que le slug de chaque article de blog et le contenu de la page soient disponibles pour chaque page qu'il génèrera :

    ```astro title="src/pages/posts/[...slug].astro"
    ---
    import { getCollection } from 'astro:content';
    import MarkdownPostLayout from '../../layouts/MarkdownPostLayout.astro';

    export async function getStaticPaths() {
      const blogEntries = await getCollection('posts');
      return blogEntries.map(entry => ({
        params: { slug: entry.slug }, props: { entry },
      }));
    }

    const { entry } = Astro.props;
    const { Content } = await entry.render();
    ---
    ```

9. Rendre le `<Content />` de l'article avec la mise en page pour les pages Markdown. Cela vous permet de spécifier une mise en page commune pour tous vos articles.

    ```astro title="src/pages/posts/[...slug].astro" ins={15-17}
    ---
    import { getCollection } from 'astro:content';
    import MarkdownPostLayout from '../../layouts/MarkdownPostLayout.astro';

    export async function getStaticPaths() {
      const blogEntries = await getCollection('posts');
      return blogEntries.map(entry => ({
        params: { slug: entry.slug }, props: { entry },
      }));
    }

    const { entry } = Astro.props;
    const { Content } = await entry.render();
    ---
    <MarkdownPostLayout frontmatter={entry.data}>
      <Content />
    </MarkdownPostLayout>
    ```

10. Supprimez la définition de `layout` dans le frontmatter de chaque article. Votre contenu est maintenant enveloppé dans un layout lors du rendu, et cette propriété n'est plus nécessaire.

    ```md title="src/content/posts/post-1.md" del={2}
    ---
    layout: ../../layouts/MarkdownPostLayout.astro
    title: 'Mon premier article de Blog'
    pubDate: 2022-07-01
    ...
    ---
    ```
</Steps>

### Remplacer `Astro.glob()` avec `getCollection()`

<Steps>
11. Partout où vous avez une liste d'articles de blog, comme la page Blog du tutoriel (`src/pages/blog.astro/`), vous devrez remplacer `Astro.glob()` par [`getCollection()`](/fr/reference/api-reference/#getcollection) comme moyen d'extraire le contenu et les métadonnées de vos fichiers Markdown.

    ```astro title="src/pages/blog.astro" "post.data" "getCollection(\"posts\")" "/posts/${post.slug}/" del={7} ins={2,8}
    ---
    import { getCollection } from "astro:content";
    import BaseLayout from "../layouts/BaseLayout.astro";
    import BlogPost from "../components/BlogPost.astro";

    const pageTitle = "Mon Blog pour apprendre Astro";
    const allPosts = await Astro.glob("../pages/posts/*.md");
    const allPosts = await getCollection("posts");
    ---
    ```

12. Vous devrez également mettre à jour les références aux données retournées pour chaque `post`. Vous trouverez maintenant vos valeurs frontmatter dans la propriété `data` de chaque objet. De plus, lorsque vous utilisez des collections, chaque objet `post` aura un `slug` de page, et non pas une URL complète.

    ```astro title="src/pages/blog.astro" "data" "/posts/$\{post.slug\}/" del={14} ins={15}
    ---
    import { getCollection } from "astro:content";
    import BaseLayout from "../layouts/BaseLayout.astro";
    import BlogPost from "../components/BlogPost.astro";

    const pageTitle = "Mon Blog pour apprendre Astro";
    const allPosts = await getCollection("posts");
    ---
    <BaseLayout pageTitle={pageTitle}>
      <p>C'est ici que j'écrirai sur mon parcours d'apprentissage d'Astro.</p>
      <ul>
        {
          allPosts.map((post) => (
            <BlogPost url={post.url} title={post.frontmatter.title} />)}
            <BlogPost url={`/posts/${post.slug}/`} title={post.data.title} />
          ))
        }
      </ul>
    </BaseLayout> 
    ```

13. Le tutoriel du projet de blog génère aussi dynamiquement une page pour chaque tag en utilisant `src/pages/tags/[tag].astro` et affiche une liste de tag dans `src/pages/tags/index.astro`. 
   
          Appliquez les mêmes changements que ci-dessus à ces deux fichiers :
      
          - récupérer les données de tous les articles de votre blog en utilisant `getCollection("posts")` au lieu d'utiliser `Astro.glob()`
          - accéder à toutes les valeurs de frontmatter en utilisant `data` au lieu de `frontmatter`
          - créer une URL de page en ajoutant le `slug` de l'article au chemin `/posts/`.
        
        La page qui génère les pages de tags individuels devient maintenant :

        ```astro title="src/pages/tags/[tag].astro" "post.data.tags" "getCollection(\"posts\")" "post.data.title" ins={2} "/posts/${post.slug}/"
        ---
        import { getCollection } from "astro:content";
        import BaseLayout from "../../layouts/BaseLayout.astro";
        import BlogPost from "../../components/BlogPost.astro";

        export async function getStaticPaths() {
          const allPosts = await getCollection("posts");
          const uniqueTags = [...new Set(allPosts.map((post) => post.data.tags).flat())];

          return uniqueTags.map((tag) => {
            const filteredPosts = allPosts.filter((post) =>
              post.data.tags.includes(tag)
            );
            return {
              params: { tag },
              props: { posts: filteredPosts },
            };
          });
        }
        
        const { tag } = Astro.params;
        const { posts } = Astro.props;
        ---

        <BaseLayout pageTitle={tag}>
            <p>Article contenant le tag {tag}</p>
            <ul>
                { posts.map((post) => <BlogPost url={`/posts/${post.slug}/`} title={post.data.title} />) }
            </ul>
        </BaseLayout>
        ```

        <Box icon="puzzle-piece">
          ### Essayez vous-même - Mettez à jour la requête dans la page Tag Index

           Importez et utilisez `getCollection` pour récupérer les tags utilisés dans les articles du blog sur `src/pages/tags/index.astro`, en suivant les [mêmes étapes que ci-dessus](#remplacer-astroglob-avec-getcollection).

          <details>
          <summary>Montrez moi le code.</summary>
          ```astro title="src/pages/tags/index.astro" "post.data" "getCollection(\"posts\")" ins={2}
          ---
          import { getCollection } from "astro:content";
          import BaseLayout from "../../layouts/BaseLayout.astro";     
          const allPosts = await getCollection("posts");
          const tags = [...new Set(allPosts.map((post) => post.data.tags).flat())];
          const pageTitle = "Tag Index";
          ---
          ...
          ```
          </details>
      </Box>
</Steps>

### Mettez à jour les valeurs du frontmatter pour qu'elles correspondent à votre schéma.

<Steps>
14. Si nécessaire, mettez à jour toutes les valeurs frontmatter dans votre projet, comme dans votre mise en page, qui ne correspondent pas à votre schéma de collections. 

    Dans l'exemple du tutoriel sur les blogs, `pubDate` était une chaîne de caractères. Maintenant, selon le schéma qui définit les types pour le frontmatter post, `pubDate` sera un 
    objet `Date`
    
    Pour rendre la date dans la mise en page de l'article de blog, convertissez-la en chaîne de caractères :

    ```astro title="src/layouts/MarkdownPostLayout.astro" ins="toString()"
    ...
    <BaseLayout pageTitle={frontmatter.title}>
      <p>{frontmatter.pubDate.toString().slice(0,10)}</p>
      <p><em>{frontmatter.description}</em></p>
      <p>Écrit par: {frontmatter.author}</p>
      <img src={frontmatter.image.url} width="300" alt={frontmatter.image.alt} />
    ...
    ```
</Steps>

### Mettre à jour la fonction RSS

<Steps>
15. Enfin, le projet tutoriel de blog inclut un flux RSS. Cette fonction doit également utiliser `getCollection()` pour renvoyer des informations sur les articles de votre blog. Vous générerez ensuite les éléments RSS à l'aide de l'objet `data` renvoyé.

    ```js title="src/pages/rss.xml.js" del={2,11} ins={3,6,12-17}
    import rss from '@astrojs/rss';
    import { pagesGlobToRssItems } from '@astrojs/rss';
    import { getCollection } from 'astro:content';

    export async function GET(context) {
      const posts = await getCollection("posts");
      return rss({
        title: 'Apprendre Astro | Blog',
        description: 'Ma journée pour apprendre Astro',
        site: context.site,
        items: await pagesGlobToRssItems(import.meta.glob('./**/*.md')),
        items: posts.map((post) => ({
          title: post.data.title,
          pubDate: post.data.pubDate,
          description: post.data.description,
          link: `/posts/${post.slug}/`,
        })),
        customData: `<language>fr-fr</language>`,
      })
    }
    ```
</Steps>

Pour un exemple complet du tutoriel sur les blogs utilisant des collections de contenus, voir la [branche Collections de contenus](https://github.com/withastro/blog-tutorial-demo/tree/content-collections) du répertoire du tutoriel.
